package com.cold.demo.web.config.handlemapping;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Predicate;

/**
 * 自定义 HandleMapping 处理器
 *
 * @author: zyc
 */
@Component
public class MyHandleMapping extends AbstractHandlerMapping implements HandlerMapping, Ordered {


    private Map<String, List<BeanAndMethod>> mapping;
    HandlerInterceptor[] handlerInterceptors;

    public MyHandleMapping(@Autowired(required = false) HandlerInterceptor[] handlerInterceptors,
                           RequestMethodProcessor requestMethodProcessor) {
        super();
        this.mapping = requestMethodProcessor.getMethodMap();
        this.handlerInterceptors = handlerInterceptors;
    }


    @Override
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        String servletPath = request.getServletPath();

        Map<String, List<BeanAndMethod>> mapping = this.mapping;
        if (mapping.containsKey(servletPath)) {

            Set<String> passingUrl = new HashSet<>();
            BeanAndMethod determined = getDetermined(servletPath, mapping,passingUrl);

            Object        bean       = determined.getBean();
            Method        method     = determined.getMethod();
            return new HandlerExecutionChain(new MyHandlerMethod(bean, method), handlerInterceptors);
        }
        return null;
    }

    private BeanAndMethod getDetermined(String servletPath, Map<String, List<BeanAndMethod>> mapping,Set<String> passingUrl ) {
        passingUrl.add(servletPath);
        List<BeanAndMethod> list          = mapping.get(servletPath);
        BeanAndMethod       beanAndMethod = list.get(0);
        String[]            originalRequestUrls = beanAndMethod.getOriginalRequestUrl();
        if (originalRequestUrls!=null && originalRequestUrls.length>0){
            for (String originalRequestUrl : originalRequestUrls) {
                if (mapping.containsKey(originalRequestUrl)){
                    if (passingUrl.contains(originalRequestUrl)){
                        throw new IllegalArgumentException("重复的replaceUrl配置-->" + originalRequestUrl);
                    }
                    return getDetermined(originalRequestUrl,mapping,passingUrl);
                }
            }
        }
        return beanAndMethod;
    }




    @Override
    public int getOrder() {
        return -1;
    }
}
